package com.sibbay.syncbox.syncdb;

import com.sibbay.syncbox.Config;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public final class SyncDatabase {
	private static final String TAG = SyncDatabase.class.getSimpleName();

	private final SyncDbOpenHelper mSyncDbOpenHelper;
	
	private SyncDatabase(Context context) {
		mSyncDbOpenHelper = new SyncDbOpenHelper(context);
	}
	
	private volatile static SyncDatabase sSyncDatabase; 
	
	public static SyncDatabase getInstance(final Context context) {
		if (sSyncDatabase == null) {
			sSyncDatabase = new SyncDatabase(context.getApplicationContext());
		}
		return sSyncDatabase;
	}
	
	public RowIterator getRowIterator(int fileType) {
		final SQLiteDatabase db = mSyncDbOpenHelper.getReadableDatabase();
		final Cursor cr = db.query(
						SyncTableConst.SYNC_TABLE_NAME, null, 
						SyncTableConst.KEY_TYPE + " = " + fileType, null, null, null, null);
		if (cr != null)
			return new RowIterator(cr);
		
		return null;
	}
	
	public boolean hasName(final String name) {
		final SQLiteDatabase db = mSyncDbOpenHelper.getReadableDatabase();
		final Cursor cr = db.query(
						SyncTableConst.SYNC_TABLE_NAME, null, 
						SyncTableConst.KEY_NAME + " == '" + name + "'", null, null, null, null);
		if (cr == null)
			return false;
		
		final int ret = cr.getCount();
		cr.close();
		if (Config.DEBUG && ret != 1) {
			Log.d(TAG, "hasName name: " + name + " not 1 row");
		}
		return ret > 0;
	}
	
	// delete all names starts from 'name'
	public int deleteName(final String name) {
		final SQLiteDatabase db = mSyncDbOpenHelper.getWritableDatabase();
		final int ret = db.delete(SyncTableConst.SYNC_TABLE_NAME, SyncTableConst.KEY_NAME + " like '" + name + "%'", null);
		if (Config.DEBUG) {
			Log.d(TAG, "deleteName name: " + name + " row: " + ret);
		}
		return ret;
	}

	public long insertName(final String name, final int fileType, final long lastModified) {
		final SQLiteDatabase db = mSyncDbOpenHelper.getWritableDatabase();
		final ContentValues values = new ContentValues();
		values.put(SyncTableConst.KEY_NAME, name);
		values.put(SyncTableConst.KEY_TYPE, fileType);
		values.put(SyncTableConst.KEY_LAST_MODIFIED, lastModified);
		values.put(SyncTableConst.KEY_STATUS, SyncConst.KEY_STATUS_READY);
		final long ret = db.insert(SyncTableConst.SYNC_TABLE_NAME, null, values);
		if (Config.DEBUG && ret < 0) {
			Log.d(TAG, "insertName cannot insert");
		}
		return ret;
	}

	public int changeLastModified(final String name, final long lastModified) {
		final SQLiteDatabase db = mSyncDbOpenHelper.getWritableDatabase();
		final ContentValues values = new ContentValues();
		values.put(SyncTableConst.KEY_LAST_MODIFIED, lastModified);
		final int ret = db.update(SyncTableConst.SYNC_TABLE_NAME, values, SyncTableConst.KEY_NAME + " == '" + name + "'", null);
		if (Config.DEBUG && ret != 1) {
			Log.d(TAG, "changeLastModified name: " + name + " not 1 row");
		}
		return ret;
	}

	public int changeStatus(final String name, final int status) {
		final SQLiteDatabase db = mSyncDbOpenHelper.getWritableDatabase();
		final ContentValues values = new ContentValues();
		values.put(SyncTableConst.KEY_STATUS, status);
		final int ret = db.update(SyncTableConst.SYNC_TABLE_NAME, values, SyncTableConst.KEY_NAME + " == '" + name + "'", null);
		if (Config.DEBUG && ret != 1) {
			Log.d(TAG, "changeStatus name: " + name + " not 1 row");
		}
		return ret;
	}
	
	public static final class RowIterator {
		
		final Cursor mCursor;
		
		private RowIterator(final Cursor cr) {
			mCursor = cr;
		}
		
		// iterators 
		
		public boolean moveToFirst() {
			return mCursor.moveToFirst();
		}
		
		public boolean moveToNext() {
			return mCursor.moveToNext();
		}
		
		// always close the iterator
		public void close() {
			mCursor.close();
		}
		
		/// wrappers for table fields
		
		public String getName() {
			return mCursor.getString(SyncTableConst.KEY_NAME_IDX);
		}
		
		public long getLastModified() {
			return mCursor.getLong(SyncTableConst.KEY_LAST_MODIFIED_IDX);
		}
		
		///
		
		@Override
		protected void finalize() throws Throwable {
			if (!mCursor.isClosed())
				mCursor.close();
			
		    super.finalize();
		}
	}

	public interface SyncConst {
	    // keys values
		public static final int KEY_TYPE_DIR = 1;
		public static final int KEY_TYPE_FILE = 2;
	    
		public static final int KEY_STATUS_READY = 1;		// ready to sync
		public static final int KEY_STATUS_PROGRESS = 2;	// in progress
		public static final int KEY_STATUS_DONE = 3;		// sync is done
	}
	
	interface SyncTableConst {
	    // sync table

	    // sync table keys
	    static final String KEY_NAME = "name";		// file name
	    static final String KEY_TYPE = "type";		// directory, file
	    static final String KEY_LAST_MODIFIED = "last_modified";	// time of last modified
	    static final String KEY_STATUS = "status";	// status
	    // sync table key indexes
	    static final int KEY_NAME_IDX 	= 1;		// file name
	    static final int KEY_TYPE_IDX 	= 2;		// directory, file
	    static final int KEY_LAST_MODIFIED_IDX = 3;		// time of last modified
	    static final int KEY_STATUS_IDX = 4;		// status

	    static final String SYNC_TABLE_NAME = "sync";
	    static final String SYNC_TABLE_CREATE =
	                "CREATE TABLE " + SYNC_TABLE_NAME + " (" +
	                KEY_NAME + 			" TEXT NOT NULL UNIQUE, " +
	                KEY_TYPE + 			" INTEGER NOT NULL, " +
	                KEY_LAST_MODIFIED +	" INTEGER NOT NULL, " +
	                KEY_STATUS +		" INTEGER NOT NULL " +
	                ");";
	}
	
	///
	
	private static final class SyncDbOpenHelper extends SQLiteOpenHelper {

	    private static final int DATABASE_VERSION = 1;
	    private static final String DATABASE_NAME = "sync.db";
	    
	    SyncDbOpenHelper(Context context) {
	        super(context, DATABASE_NAME, null, DATABASE_VERSION);
	    }

	    @Override
	    public void onCreate(SQLiteDatabase db) {
	        db.execSQL(SyncTableConst.SYNC_TABLE_CREATE);
	    }

		@Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			// nothing to do yet
        }
	}
}
